package cz.muni.fi.pa165.languageschool.web;

import cz.muni.fi.pa165.languageschool.DataFetchException;
import cz.muni.fi.pa165.languageschool.dto.CourseTO;
import cz.muni.fi.pa165.languageschool.service.LectureService;
import cz.muni.fi.pa165.languageschool.dto.LectureTO;
import cz.muni.fi.pa165.languageschool.dto.LecturerTO;
import cz.muni.fi.pa165.languageschool.dto.StudentTO;
import cz.muni.fi.pa165.languageschool.service.CourseService;
import cz.muni.fi.pa165.languageschool.service.LecturerService;
import cz.muni.fi.pa165.languageschool.service.StudentService;
import static cz.muni.fi.pa165.languageschool.web.BaseActionBean.escapeHTML;
import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.LocalizableMessage;
import net.sourceforge.stripes.action.RedirectResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.UrlBinding;
import net.sourceforge.stripes.integration.spring.SpringBean;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import net.sourceforge.stripes.validation.ValidationErrorHandler;
import net.sourceforge.stripes.validation.ValidationErrors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Action bean for handling with requests from lectures section
 *
 * @author Michal Fučík (395624) michal.fuca.fucik(at)gmail.com
 */
@UrlBinding("/lectures/{$event}/{activity.id}")
public class LectureActionBean extends BaseActionBean implements ValidationErrorHandler {

    @ValidateNestedProperties(value = {
        @Validate(on = {"addLecture", "saveLecture"}, field = "topicDescription", required = true),
        @Validate(on = {"addLecture", "saveLecture"}, field = "time", required = true),
        @Validate(on = {"addLecture", "saveLecture"}, field = "tpDay", required = true),
        @Validate(on = {"addLecture", "saveLecture"}, field = "label", required = true)
    })

    final static Logger log = LoggerFactory.getLogger(LectureActionBean.class);

    @SpringBean
    protected LectureService lectureService;
    @SpringBean
    protected LecturerService lecturerService;
    @SpringBean
    protected CourseService courseService;
    @SpringBean
    protected StudentService studentService;

    private List<LecturerTO> lecturers;
    private List<LectureTO> lectures;
    private List<CourseTO> courses;
    private List<StudentTO> students;
    private List<StudentTO> enrolledStudents;

    @Validate(on = {"addLecture", "saveLecture"}, required = true)
    private Long courseId;
    @Validate(on = {"addLecture", "saveLecture"}, required = true)
    private Long lecturerId;

    private String time;

    private Long studentId;

    private CourseTO courseTO;
    private LecturerTO lecturerTO;
    private LectureTO lectureTO;

    // -----------------------------------------------------------------------------
    public void setTime(String time) {
        this.time = time;
    }

    public void setLecturerId(Long lecturerId) {
        this.lecturerId = lecturerId;
    }

    public void setLecturerTO(LecturerTO lecturerTO) {
        this.lecturerTO = lecturerTO;
    }

    public List<LecturerTO> getLecturers() {
        return lecturers;
    }

    public Long getCourseId() {
        return courseId;
    }

    public void setCourseId(Long courseId) {
        this.courseId = courseId;
    }

    public LectureTO getLecture() {
        return lectureTO;
    }

    public void setLecture(LectureTO lecture) {
        this.lectureTO = lecture;
    }

    public List<CourseTO> getCourses() {
        return courses;
    }

    public void setCourses(List<CourseTO> courses) {
        this.courses = courses;
    }

    public List<LectureTO> getLectures() {
        return lectures;
    }

    public void setLectures(List<LectureTO> lectures) {
        this.lectures = lectures;
    }

    public List<StudentTO> getStudents() {
        return students;
    }

    public void setStudents(List<StudentTO> students) {
        this.students = students;
    }

    public StudentService getStudentService() {
        return studentService;
    }

    public void setStudentService(StudentService studentService) {
        this.studentService = studentService;
    }

    public List<StudentTO> getEnrolledStudents() {
        return enrolledStudents;
    }

    public LectureTO getLectureTO() {
        return lectureTO;
    }

    public void setStudentId(Long studentId) {
        this.studentId = studentId;
    }

// -----------------------------------------------------------------------------
    @DefaultHandler
    public Resolution list() {
        log.info("***** WEB Lectures list (default handler)");
        lecturers = (List<LecturerTO>) lecturerService.getAllLecturers();
        lectures = (List<LectureTO>) lectureService.getAllLectures();
        courses = (List<CourseTO>) courseService.getAllCourses();
        return new ForwardResolution("/jsp/lecture/list.jsp");
    }

    public Resolution addLecture() {

        courseTO = courseService.getCourse(courseId);
        lecturerTO = lecturerService.getLecturer(lecturerId);

        if (!lecturerTO.getLanguages().contains(courseTO.getTaughtLanguage())) {
            this.getContext().getMessages().add(
                    new LocalizableMessage("lecture.add.failure.lecturer.language"));
            return new RedirectResolution(this.getClass(), "list");
        }

        lectureTO.setCourse(courseTO);
        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm");
        Date date = new Date();
        try {
            if (time != null) {
                date = sdf.parse(time);
            }

        } catch (ParseException ex) {
            log.error(ex.getMessage(), ex);
        }

        lectureTO.setTpTime(new Time(date.getTime()));
        lectureService.createLecture(lectureTO);
        log.info("***** WEB LectureActionBean addLecture: {}", lectureTO);
        lectureService.setLecturerToLecture(lectureTO.getId(), lecturerTO);
        this.getContext().getMessages().add(
                new LocalizableMessage("lecture.add.success",
                        escapeHTML(lectureTO.getLabel())));
        return new RedirectResolution(this.getClass(), "list");
    }

    public Resolution deleteLecture() {
        String id = this.getContext().getRequest().getParameter("lecture.id");
        lectureTO = lectureService.getLecture(Long.parseLong(id));
        log.info("***** WEB LectureActionBean deleteLecture: {}", id);
        try {
            lectureService.deleteLecture(lectureTO);
        } catch (Exception ex) {
            log.error("LECTURE {} CANNOT BE DELETED, IT DEPENDS ON COURSE/LECTURER", lectureTO.getId());
            this.getContext().getMessages().add(
                    new LocalizableMessage("lecture.delete.failure",
                            escapeHTML(lectureTO.getLabel())));
            return new RedirectResolution(this.getClass(), "list");
        }
        this.getContext().getMessages().add(
                new LocalizableMessage("lecture.delete.success",
                        escapeHTML(lectureTO.getLabel())));
        log.info("Lecture bas been successfuly deleted. " + lectureTO);
        return new RedirectResolution(this.getClass(), "list");
    }

    public Resolution editLecture() {
        log.info("***** WEB LectureActionBean editLecture: {}", lectureTO);

        String id = getContext().getRequest().getParameter("lecture.id");
        if (id == null) {
            return new ForwardResolution(this.getClass(), "list");
        }

        lectureTO = lectureService.getLecture(Long.parseLong(id));
        lecturers = (List<LecturerTO>) lecturerService.getAllLecturers();
        courses = (List<CourseTO>) courseService.getAllCourses();

        lecturerTO = lectureTO.getLecturer();
        if (lecturerTO != null) {
            lecturerId = lecturerTO.getId();
        }

        courseTO = lectureTO.getCourse();
        if (courseTO != null) {
            courseId = courseTO.getId();
        }
        return new ForwardResolution("/jsp/lecture/edit.jsp");
    }

    public Resolution updateLecture() {
        log.info("***** WEB LectureActionBean updateLecture: {}", lectureTO);
        lecturerTO = lecturerService.getLecturer(lecturerId);
        courseTO = courseService.getCourse(courseId);

        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm");
        Date date = new Date();

        try {
            if (time != null) {
                date = sdf.parse(time);
            }
        } catch (ParseException ex) {
            log.error(ex.getMessage(), ex);
        }
        lectureTO.setTpTime(new Time(date.getTime()));
        lectureTO.setCourse(courseTO);
        lectureService.updateLecture(lectureTO);
        lectureService.setLecturerToLecture(lectureTO.getId(), lecturerTO);
        return new RedirectResolution(this.getClass(), "list");
    }

    public Resolution detail() {

        String id = getContext().getRequest().getParameter("lecture.id");
        if (id == null) {
            return new ForwardResolution(this.getClass(), "list");
        }
        try {
            lectureTO = lectureService.getLecture(Long.parseLong(id));
            enrolledStudents = lectureService.getEnrolledStudents(lectureTO);
            students = (List<StudentTO>) studentService.getAllStudents();
        } catch (DataFetchException ex) {
            this.getContext().getMessages().add(
                    new LocalizableMessage("detail.failure",
                            escapeHTML(lectureTO.getLabel())));

            return new ForwardResolution(this.getClass(), "list");
        }
        log.info("***** WEB LectureActionBean studentsList: {}", lectureTO);

        return new ForwardResolution("/jsp/lecture/detail.jsp");
    }

    public Resolution enrollStudent() {
        StudentTO studentTO = null;
        String lectureId = getContext().getRequest().getParameter("lecture.id");
        if (lectureId == null) {
            return new ForwardResolution(this.getClass(), "list");
        }
        try {
            studentTO = studentService.getStudent(studentId);
            lectureTO = lectureService.getLecture(Long.parseLong(lectureId));
            log.info("***** WEB LectureActionBean enrollStudent: {} for lecture: {}", studentTO, lectureTO);
        } catch (DataFetchException ex) {
            this.getContext().getMessages().add(new LocalizableError("student.enroll.failure.enrolled",
                    escapeHTML(lectureTO.getLabel()) + " - " + escapeHTML(lectureTO.getCourse().getName())));
            return new RedirectResolution("/lectures/list");
        }
        try {
            lectureService.enrollStudent(lectureTO, studentTO);
        } catch (IllegalStateException x) {
            this.getContext().getMessages().add(new LocalizableError("student.enroll.failure.enrolled",
                    escapeHTML(lectureTO.getLabel()) + " - " + escapeHTML(lectureTO.getCourse().getName())));
            return new RedirectResolution("/lectures/detail?lecture.id=" + lectureTO.getId());
        }
        return new RedirectResolution("/lectures/detail?lecture.id=" + lectureTO.getId());
    }

    public Resolution disenrollStudent() {
        StudentTO studentTO = null;
        String ids = getContext().getRequest().getParameter("student.id");
        String idl = getContext().getRequest().getParameter("lecture.id");
        if (ids == null || idl == null) {
            return new RedirectResolution(this.getClass(), "detail");
        }
        try {
            studentTO = studentService.getStudent(Long.parseLong(ids));
            lectureTO = lectureService.getLecture(Long.parseLong(idl));
            lectureService.disenrollStudent(lectureTO, studentTO);
            log.info("***** WEB LectureActionBean disenrollStudent: {} from lecture: {}", studentTO, lectureTO);
        } catch (DataFetchException | NullPointerException ex) {
            this.getContext().getMessages().add(new LocalizableError("student.disenroll.failure.lower",
                    escapeHTML(lectureTO.getLabel()) + " - " + escapeHTML(lectureTO.getCourse().getName())));
            return new RedirectResolution("/lectures/list");
        }
        return new RedirectResolution("/lectures/detail?lecture.id=" + lectureTO.getId());
    }

    public Resolution cancelEdit() {
        log.info("***** WEB LectureActionBean cancelEdit");
        return new RedirectResolution(this.getClass(), "list");
    }

    public Resolution cancelDetail() {
        log.info("***** WEB LectureActionBean cancelDetail");
        return new RedirectResolution(this.getClass(), "list");
    }

    @Override
    public Resolution handleValidationErrors(ValidationErrors errors) throws Exception {
        lectures = (List) lectureService.getAllLectures();
        courses = (List) courseService.getAllCourses();
        lecturers = (List) lecturerService.getAllLecturers();
        return null;
    }
}
